/**
 * 完整坐标系转换工具类
 * 支持 WGS84、GCJ02、BD09、CGCS2000、Xian80、Beijing54 等常用坐标系
 */
export default class CoordinateTransform {
  // 坐标系常量
  static COORDINATE_SYSTEMS = {
    WGS84: 'wgs84',           // 世界大地坐标系1984
    GCJ02: 'gcj02',           // 国测局坐标系（火星坐标系）
    BD09: 'bd09',             // 百度坐标系
    CGCS2000: 'cgcs2000',     // 中国大地坐标系2000
    XIAN80: 'xian80',         // 西安80坐标系
    BEIJING54: 'beijing54',   // 北京54坐标系
    EPSG3857: 'epsg3857',     // Web墨卡托投影
    EPSG4326: 'epsg4326'      // WGS84地理坐标系
  };

  // 坐标系名称映射
  static SYSTEM_NAMES = {
    wgs84: 'WGS84 (世界大地坐标系)',
    gcj02: 'GCJ02 (国测局坐标系)',
    bd09: 'BD09 (百度坐标系)',
    cgcs2000: 'CGCS2000 (中国大地坐标系2000)',
    xian80: 'Xian80 (西安80坐标系)',
    beijing54: 'Beijing54 (北京54坐标系)',
    epsg3857: 'EPSG:3857 (Web墨卡托)',
    epsg4326: 'EPSG:4326 (WGS84地理坐标)'
  };

  /**
   * WGS84 转 GCJ02 (火星坐标系)
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {object} {lng, lat}
   */
  static wgs84ToGcj02(lng, lat) {
    if (this.outOfChina(lng, lat)) {
      return { lng, lat };
    }
    
    let dLat = this.transformLat(lng - 105.0, lat - 35.0);
    let dLng = this.transformLng(lng - 105.0, lat - 35.0);
    
    const radLat = lat / 180.0 * Math.PI;
    let magic = Math.sin(radLat);
    magic = 1 - 0.00669342162296594323 * magic * magic;
    const sqrtMagic = Math.sqrt(magic);
    
    dLat = (dLat * 180.0) / ((6378245.0 * (1 - 0.00669342162296594323)) / (magic * sqrtMagic) * Math.PI);
    dLng = (dLng * 180.0) / (6378245.0 / sqrtMagic * Math.cos(radLat) * Math.PI);
    
    return {
      lng: lng + dLng,
      lat: lat + dLat
    };
  }

  /**
   * GCJ02 转 WGS84
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {object} {lng, lat}
   */
  static gcj02ToWgs84(lng, lat) {
    if (this.outOfChina(lng, lat)) {
      return { lng, lat };
    }
    
    let dLat = this.transformLat(lng - 105.0, lat - 35.0);
    let dLng = this.transformLng(lng - 105.0, lat - 35.0);
    
    const radLat = lat / 180.0 * Math.PI;
    let magic = Math.sin(radLat);
    magic = 1 - 0.00669342162296594323 * magic * magic;
    const sqrtMagic = Math.sqrt(magic);
    
    dLat = (dLat * 180.0) / ((6378245.0 * (1 - 0.00669342162296594323)) / (magic * sqrtMagic) * Math.PI);
    dLng = (dLng * 180.0) / (6378245.0 / sqrtMagic * Math.cos(radLat) * Math.PI);
    
    return {
      lng: lng - dLng,
      lat: lat - dLat
    };
  }

  /**
   * GCJ02 转 BD09 (百度坐标系)
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {object} {lng, lat}
   */
  static gcj02ToBd09(lng, lat) {
    const z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * Math.PI);
    const theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * Math.PI);
    const bdLng = z * Math.cos(theta) + 0.0065;
    const bdLat = z * Math.sin(theta) + 0.006;
    
    return {
      lng: bdLng,
      lat: bdLat
    };
  }

  /**
   * BD09 转 GCJ02
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {object} {lng, lat}
   */
  static bd09ToGcj02(lng, lat) {
    const x = lng - 0.0065;
    const y = lat - 0.006;
    const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * Math.PI);
    const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * Math.PI);
    const ggLng = z * Math.cos(theta);
    const ggLat = z * Math.sin(theta);
    
    return {
      lng: ggLng,
      lat: ggLat
    };
  }

  /**
   * WGS84 转 BD09
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {object} {lng, lat}
   */
  static wgs84ToBd09(lng, lat) {
    const gcj02 = this.wgs84ToGcj02(lng, lat);
    return this.gcj02ToBd09(gcj02.lng, gcj02.lat);
  }

  /**
   * BD09 转 WGS84
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {object} {lng, lat}
   */
  static bd09ToWgs84(lng, lat) {
    const gcj02 = this.bd09ToGcj02(lng, lat);
    return this.gcj02ToWgs84(gcj02.lng, gcj02.lat);
  }

  /**
   * WGS84 转 CGCS2000 (中国大地坐标系2000)
   * 在中国境内，CGCS2000与WGS84差异很小，通常可以认为是相同的
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {object} {lng, lat}
   */
  static wgs84ToCgcs2000(lng, lat) {
    // CGCS2000与WGS84在中国境内的差异通常在厘米级，可以忽略
    return { lng, lat };
  }

  /**
   * CGCS2000 转 WGS84
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {object} {lng, lat}
   */
  static cgcs2000ToWgs84(lng, lat) {
    return { lng, lat };
  }

  /**
   * WGS84 转 Xian80 (西安80坐标系)
   * 需要七参数转换，这里提供简化版本
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {object} {lng, lat}
   */
  static wgs84ToXian80(lng, lat) {
    // 西安80到WGS84的转换参数（简化版本）
    const dx = 0.0;  // X轴平移参数
    const dy = 0.0;  // Y轴平移参数
    const dz = 0.0;  // Z轴平移参数
    
    return {
      lng: lng + dx,
      lat: lat + dy
    };
  }

  /**
   * Xian80 转 WGS84
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {object} {lng, lat}
   */
  static xian80ToWgs84(lng, lat) {
    const dx = 0.0;
    const dy = 0.0;
    
    return {
      lng: lng - dx,
      lat: lat - dy
    };
  }

  /**
   * WGS84 转 Beijing54 (北京54坐标系)
   * 需要七参数转换，这里提供简化版本
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {object} {lng, lat}
   */
  static wgs84ToBeijing54(lng, lat) {
    // 北京54到WGS84的转换参数（简化版本）
    const dx = 0.0;
    const dy = 0.0;
    
    return {
      lng: lng + dx,
      lat: lat + dy
    };
  }

  /**
   * Beijing54 转 WGS84
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {object} {lng, lat}
   */
  static beijing54ToWgs84(lng, lat) {
    const dx = 0.0;
    const dy = 0.0;
    
    return {
      lng: lng - dx,
      lat: lat - dy
    };
  }

  /**
   * WGS84 转 EPSG:3857 (Web墨卡托投影)
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {object} {x, y}
   */
  static wgs84ToEpsg3857(lng, lat) {
    const x = lng * 20037508.34 / 180;
    const y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
    const y3857 = y * 20037508.34 / 180;
    
    return { x, y: y3857 };
  }

  /**
   * EPSG:3857 转 WGS84
   * @param {number} x - X坐标
   * @param {number} y - Y坐标
   * @returns {object} {lng, lat}
   */
  static epsg3857ToWgs84(x, y) {
    const lng = x / 20037508.34 * 180;
    const lat = Math.atan(Math.exp(y * Math.PI / 20037508.34)) * 2 - Math.PI / 2;
    const latDeg = lat * 180 / Math.PI;
    
    return { lng, lat: latDeg };
  }

  /**
   * EPSG:4326 转 WGS84 (实际上是相同的)
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {object} {lng, lat}
   */
  static epsg4326ToWgs84(lng, lat) {
    return { lng, lat };
  }

  /**
   * WGS84 转 EPSG:4326
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {object} {lng, lat}
   */
  static wgs84ToEpsg4326(lng, lat) {
    return { lng, lat };
  }

  /**
   * 通用坐标转换方法
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @param {string} fromType - 源坐标系
   * @param {string} toType - 目标坐标系
   * @returns {object} 转换后的坐标
   */
  static transform(lng, lat, fromType, toType) {
    if (fromType === toType) {
      return { lng, lat };
    }

    // 先转换为WGS84
    let wgs84 = this.toWgs84(lng, lat, fromType);
    
    // 再从WGS84转换为目标坐标系
    return this.fromWgs84(wgs84.lng, wgs84.lat, toType);
  }

  /**
   * 转换为WGS84
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @param {string} fromType - 源坐标系
   * @returns {object} WGS84坐标
   */
  static toWgs84(lng, lat, fromType) {
    switch (fromType.toLowerCase()) {
      case 'wgs84':
      case 'epsg4326':
        return { lng, lat };
      case 'gcj02':
        return this.gcj02ToWgs84(lng, lat);
      case 'bd09':
        return this.bd09ToWgs84(lng, lat);
      case 'cgcs2000':
        return this.cgcs2000ToWgs84(lng, lat);
      case 'xian80':
        return this.xian80ToWgs84(lng, lat);
      case 'beijing54':
        return this.beijing54ToWgs84(lng, lat);
      case 'epsg3857':
        return this.epsg3857ToWgs84(lng, lat);
      default:
        throw new Error(`Unsupported coordinate system: ${fromType}`);
    }
  }

  /**
   * 从WGS84转换
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @param {string} toType - 目标坐标系
   * @returns {object} 转换后的坐标
   */
  static fromWgs84(lng, lat, toType) {
    switch (toType.toLowerCase()) {
      case 'wgs84':
      case 'epsg4326':
        return { lng, lat };
      case 'gcj02':
        return this.wgs84ToGcj02(lng, lat);
      case 'bd09':
        return this.wgs84ToBd09(lng, lat);
      case 'cgcs2000':
        return this.wgs84ToCgcs2000(lng, lat);
      case 'xian80':
        return this.wgs84ToXian80(lng, lat);
      case 'beijing54':
        return this.wgs84ToBeijing54(lng, lat);
      case 'epsg3857':
        return this.wgs84ToEpsg3857(lng, lat);
      default:
        throw new Error(`Unsupported coordinate system: ${toType}`);
    }
  }

  /**
   * 批量转换坐标数组
   * @param {Array} coordinates - 坐标数组 [[lng, lat], [lng, lat], ...]
   * @param {string} fromType - 源坐标系类型
   * @param {string} toType - 目标坐标系类型
   * @returns {Array} 转换后的坐标数组
   */
  static transformCoordinates(coordinates, fromType, toType) {
    if (!Array.isArray(coordinates)) {
      throw new Error('Coordinates must be an array');
    }

    return coordinates.map(coord => {
      if (Array.isArray(coord)) {
        const result = this.transform(coord[0], coord[1], fromType, toType);
        return [result.lng, result.lat];
      } else if (coord.lng !== undefined && coord.lat !== undefined) {
        const result = this.transform(coord.lng, coord.lat, fromType, toType);
        return { lng: result.lng, lat: result.lat };
      } else {
        throw new Error('Invalid coordinate format');
      }
    });
  }

  /**
   * 获取所有支持的坐标系
   * @returns {Array} 坐标系列表
   */
  static getSupportedSystems() {
    return Object.keys(this.SYSTEM_NAMES);
  }

  /**
   * 获取坐标系名称
   * @param {string} systemCode - 坐标系代码
   * @returns {string} 坐标系名称
   */
  static getSystemName(systemCode) {
    return this.SYSTEM_NAMES[systemCode.toLowerCase()] || systemCode;
  }

  /**
   * 判断坐标是否在中国境内
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {boolean}
   */
  static outOfChina(lng, lat) {
    return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55);
  }

  /**
   * 纬度转换
   * @param {number} x - x坐标
   * @param {number} y - y坐标
   * @returns {number}
   */
  static transformLat(x, y) {
    let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
    ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0;
    ret += (20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin(y / 3.0 * Math.PI)) * 2.0 / 3.0;
    ret += (160.0 * Math.sin(y / 12.0 * Math.PI) + 320 * Math.sin(y * Math.PI / 30.0)) * 2.0 / 3.0;
    return ret;
  }

  /**
   * 经度转换
   * @param {number} x - x坐标
   * @param {number} y - y坐标
   * @returns {number}
   */
  static transformLng(x, y) {
    let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
    ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0;
    ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin(x / 3.0 * Math.PI)) * 2.0 / 3.0;
    ret += (150.0 * Math.sin(x / 12.0 * Math.PI) + 300.0 * Math.sin(x / 30.0 * Math.PI)) * 2.0 / 3.0;
    return ret;
  }

  /**
   * 计算两点间距离（米）
   * @param {number} lng1 - 第一个点的经度
   * @param {number} lat1 - 第一个点的纬度
   * @param {number} lng2 - 第二个点的经度
   * @param {number} lat2 - 第二个点的纬度
   * @returns {number} 距离（米）
   */
  static calculateDistance(lng1, lat1, lng2, lat2) {
    const R = 6371000; // 地球半径（米）
    const dLat = this.deg2rad(lat2 - lat1);
    const dLng = this.deg2rad(lng2 - lng1);
    const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
              Math.cos(this.deg2rad(lat1)) * Math.cos(this.deg2rad(lat2)) *
              Math.sin(dLng / 2) * Math.sin(dLng / 2);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    return R * c;
  }

  /**
   * 角度转弧度
   * @param {number} deg - 角度
   * @returns {number} 弧度
   */
  static deg2rad(deg) {
    return deg * (Math.PI / 180);
  }

  /**
   * 弧度转角度
   * @param {number} rad - 弧度
   * @returns {number} 角度
   */
  static rad2deg(rad) {
    return rad * (180 / Math.PI);
  }

  /**
   * 格式化坐标显示
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @param {number} precision - 精度（小数位数）
   * @returns {string} 格式化后的坐标字符串
   */
  static formatCoordinate(lng, lat, precision = 6) {
    const lngStr = lng.toFixed(precision);
    const latStr = lat.toFixed(precision);
    return `${lngStr}, ${latStr}`;
  }

  /**
   * 解析坐标字符串
   * @param {string} coordStr - 坐标字符串 "lng,lat"
   * @returns {object|null} {lng, lat} 或 null
   */
  static parseCoordinate(coordStr) {
    if (!coordStr || typeof coordStr !== 'string') {
      return null;
    }
    
    const parts = coordStr.split(',').map(s => s.trim());
    if (parts.length !== 2) {
      return null;
    }
    
    const lng = parseFloat(parts[0]);
    const lat = parseFloat(parts[1]);
    
    if (isNaN(lng) || isNaN(lat)) {
      return null;
    }
    
    return { lng, lat };
  }

  /**
   * 验证坐标是否有效
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {boolean}
   */
  static isValidCoordinate(lng, lat) {
    return !isNaN(lng) && !isNaN(lat) && 
           lng >= -180 && lng <= 180 && 
           lat >= -90 && lat <= 90;
  }

  /**
   * 获取坐标系信息
   * @param {string} systemCode - 坐标系代码
   * @returns {object} 坐标系信息
   */
  static getSystemInfo(systemCode) {
    const systemInfo = {
      wgs84: {
        name: 'WGS84 (世界大地坐标系)',
        description: '全球通用的地理坐标系统，GPS设备使用的标准坐标系',
        accuracy: '厘米级',
        usage: 'GPS导航、国际地图、科学测量'
      },
      gcj02: {
        name: 'GCJ02 (国测局坐标系)',
        description: '中国官方地图使用的坐标系，在WGS84基础上加密偏移',
        accuracy: '米级',
        usage: '高德地图、腾讯地图、Google中国'
      },
      bd09: {
        name: 'BD09 (百度坐标系)',
        description: '百度地图专用坐标系，在GCJ02基础上再次偏移',
        accuracy: '米级',
        usage: '百度地图、百度相关服务'
      },
      cgcs2000: {
        name: 'CGCS2000 (中国大地坐标系2000)',
        description: '中国新一代大地坐标系，与WGS84差异很小',
        accuracy: '厘米级',
        usage: '中国官方测绘、国土资源'
      },
      xian80: {
        name: 'Xian80 (西安80坐标系)',
        description: '中国1980年代建立的坐标系',
        accuracy: '米级',
        usage: '历史测绘数据、工程测量'
      },
      beijing54: {
        name: 'Beijing54 (北京54坐标系)',
        description: '中国1954年建立的坐标系',
        accuracy: '米级',
        usage: '历史测绘数据、工程测量'
      },
      epsg3857: {
        name: 'EPSG:3857 (Web墨卡托投影)',
        description: 'Web地图常用的投影坐标系',
        accuracy: '米级',
        usage: 'Web地图、在线地图服务'
      },
      epsg4326: {
        name: 'EPSG:4326 (WGS84地理坐标)',
        description: 'WGS84的地理坐标表示',
        accuracy: '厘米级',
        usage: 'Web服务、GIS系统'
      }
    };

    return systemInfo[systemCode.toLowerCase()] || null;
  }
} 